package com.hp.search_service.service;

import com.hp.common_api.entity.Brand;
import com.hp.common_api.entity.Category;
import com.hp.common_api.entity.PageResult;
import com.hp.common_api.entity.SpecParam;
import com.hp.search_service.entity.Goods;
import com.hp.search_service.entity.Search;
import com.hp.search_service.entity.SearchPageResult;
import com.hp.search_service.feign.GoodsFeignClient;
import com.hp.search_service.repository.GoodsRepository;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 商品搜索业务
 */
@Service
public class GoodsSearchService {


    @Autowired
    private GoodsRepository goodsRepository;

    @Autowired
    private GoodsFeignClient goodsFeignClient;

    /**
     * 根据关键字进行搜索
     * @return
     */
    public PageResult<Goods> search(Search search){
        //判断关键字是否为空
        if(StringUtils.isBlank(search.getKeyword())){
            return null;
        }
        //创建本地查询生成器
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
//        //在all字段中查询关键字 设置And操作符，避免分词查询时，查询无关数据
//        MatchQueryBuilder query = QueryBuilders.matchQuery("all", search.getKeyword()).operator(Operator.AND);
        BoolQueryBuilder queryByFilters = createQueryByFilters(search.getKeyword(), search.getSpecs());
        //设置查询
        builder.withQuery(queryByFilters);
        //设置分页
        builder.withPageable(PageRequest.of(search.getCurrent() - 1,search.getPageSize()));
        //设置排序字段
        if(StringUtils.isNotBlank(search.getSortBy())){
            builder.withSort(SortBuilders.fieldSort(search.getSortBy())
                    .order("DESC".equals(search.getSortType().toUpperCase())?SortOrder.DESC:SortOrder.ASC));
        }
        //对品牌id和分类的id进行聚合
        builder.addAggregation(AggregationBuilders.terms("category").field("cid3"));
        builder.addAggregation(AggregationBuilders.terms("brand").field("brandId"));
        //获得分页结果
        AggregatedPage<Goods> result = (AggregatedPage<Goods>) goodsRepository.search(builder.build());
        //通过聚合的品牌id和分类id查询品牌和分类
        List<Category> categories = getCategories(result.getAggregation("category"));
        List<Brand> brands = getBrands(result.getAggregation("brand"));
        //如果聚合的分类只有一个，就获得规格参数
        List<Map<String, Object>> specParams = null;
        if(categories.size() == 1){
            Long cid = categories.get(0).getId();
            specParams = getSpecParams(cid);
        }
        return new SearchPageResult(result.getTotalElements(),search.getCurrent(),
                result.getContent(),search.getPageSize(),brands,categories,specParams);
    }

    /**
     * 从分类聚合的结果中取分类id，查询分类对象，返回
     * @param aggregation
     * @return
     */
    public List<Category> getCategories(Aggregation aggregation){
        List<Category> categories = new ArrayList<>();
        //转换为long类型的聚合结果
        LongTerms longTerms = (LongTerms) aggregation;
        //遍历每个聚合的桶
        for(Terms.Bucket bucket : longTerms.getBuckets()){
            //获得分类的id
            long cid = bucket.getKeyAsNumber().longValue();
            //调用商品服务查分类
            Category category = goodsFeignClient.getCategoryById(cid).getBody();
            categories.add(category);
        }
        return categories;
    }

    /**
     * 从聚合结果中获得品牌
     * @param aggregation
     * @return
     */
    public List<Brand> getBrands(Aggregation aggregation){
        List<Brand> brands = new ArrayList<>();
        LongTerms longTerms = (LongTerms) aggregation;
        for(Terms.Bucket bucket : longTerms.getBuckets()){
            long brandId = bucket.getKeyAsNumber().longValue();
            Brand brand = goodsFeignClient.getBrandById(brandId).getBody();
            brands.add(brand);
        }
        return brands;
    }

    /**
     * 通过分类id查询所有规格 以 key：xx ,options: xx组织
     * @param cid
     * @return
     */
    public List<Map<String,Object>> getSpecParams(long cid){
        List<SpecParam> specParams = goodsFeignClient.getSpecParamsByCategoryId(cid).getBody();
        List<Map<String,Object>> specs = new ArrayList<>();
        specParams.forEach(param -> {
            //判断此规格是否能用于搜索 并有segemnts
            if(param.getSearching() && param.getSegments().length() > 0){
                Map<String,Object> map = new HashMap<>();
                String[] options = param.getSegments().split(",");
                map.put("key",param.getName());
                map.put("options",options);
                specs.add(map);
            }
        });
        return specs;
    }

    /**
     * 通过关键字和过滤条件创建BoolQuery
     * @param keyword
     * @param filters
     * @return
     */
    public BoolQueryBuilder createQueryByFilters(String keyword, Map<String,String> filters){
        //创建布尔查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //进行关键字的全文检索,使用must
        MatchQueryBuilder keywordQuery = QueryBuilders.matchQuery("all", keyword).operator(Operator.AND);
        boolQueryBuilder.must(keywordQuery);
        //创建filter布尔查询
        BoolQueryBuilder filterQuery = QueryBuilders.boolQuery();
        //遍历filters
        for(Map.Entry<String,String> entry : filters.entrySet()){
            String key = "";
            //品牌和分类查询的key需要特殊处理
            if("品牌".equals(entry.getKey())){
                key = "brandId";
            }else if("分类".equals(entry.getKey())){
                key = "cid3";
            }else{
                //其它的属性
                key = "specs." + entry.getKey() + ".keyword";
            }
            filterQuery.must(QueryBuilders.termQuery(key,entry.getValue()));
        }
        //设置filter
        boolQueryBuilder.filter(filterQuery);
        return boolQueryBuilder;
    }
}
